use std::thread::spawn;

use clap::Parser;
use serde::{Deserialize, Serialize};
use wtask_base::export::{json, kill_channel};
use wtask_base::{encrypt::decrypt_str_to_str, export::KillSender};
use wtask_base::error::WResult;
use wtask_app::{AppTrait, msg_func_none, AppPort};
use wtask_file::{IncomingBody, Request, Response, StatusCode, header};

use crate::basic::{parse_body_string, response_body, ResponseBody, WEB_SESSION};



#[derive(Debug, Clone, Serialize, Deserialize)]
struct PortData {
    token: String,
    local: u32,
    remote: u32,
    machine: String,
    info: String,
}

pub(crate) struct PortStorage {
    // port-forwarding killer: { port: killer }
    pub(crate) killer: KillSender<bool>,
    // port-forwarding meta: { port: meta }
    meta: PortData
}

impl Drop for PortStorage {
    fn drop(&mut self) {
        let _ = self.killer.send(true);
    }
}


pub(crate) async fn response_port(req: Request<IncomingBody>, token: &str) -> WResult<Response<ResponseBody>> {
    // header
    let req_status = req.headers().get("Status");
    let machine_id = req.headers().get("ID");
    if req_status.is_none() || machine_id.is_none() {
        let res_value = {
            let data = WEB_SESSION.port.read().await;
            let data = data.values().filter(| &v | v.meta.token.eq(token)).map(| v | &v.meta).collect::<Vec<_>>();
            json!({
                "msg": "端口转发查询完成",
                "data": data,
            })
        };
        let json = json!(res_value).to_string();
        let res = Response::builder()
            .status(StatusCode::OK)
            .header(header::CONTENT_TYPE, "application/json")
            .body(response_body(&json, token)).unwrap();
        return Ok(res);
    }
    
    let req_status = req_status.unwrap();
    let req_status = req_status.to_str().unwrap().to_lowercase().eq("true");
    let machine_id = machine_id.unwrap();
    let machine_id = decrypt_str_to_str(machine_id.to_str().unwrap(), token)?;

    let mut machine_config = None;
    let mut machine_keys = Vec::new();

    // check login
    if let Some(machines) = WEB_SESSION.login.read().await.as_ref().get(token) {
        machine_keys.extend(machines.keys().map(| v | v.to_string()));
        if let Some(config_temp) = machines.get(&machine_id) {
            machine_config = Some(config_temp.config.clone());
        }
    };
    if machine_config.is_none() {
        let json = json!({
            "msg": "登录失败",
            "data": {
                "req": machine_id,
                "all": machine_keys
            },
        }).to_string();
        let res = Response::builder()
            .status(StatusCode::UNAUTHORIZED)
            .header(header::CONTENT_TYPE, "application/json")
            .body(response_body(&json, token)).unwrap();
        return Ok(res);
    }
    let machine_config = machine_config.unwrap();

    // port_config
    let body_de = parse_body_string(req, token).await?;
    let port_config = AppPort::try_parse_from(body_de.split(" "));
    if port_config.is_err() {
        let json = json!({
            "msg": "参数解析失败",
            "data": port_config.err().unwrap().to_string(),
        }).to_string();
        let res = Response::builder()
            .status(StatusCode::BAD_REQUEST)
            .header(header::CONTENT_TYPE, "application/json")
            .body(response_body(&json, token)).unwrap();
        return Ok(res);
    }
    let port_config = port_config.unwrap();
    let port_local = if let Some(port) = port_config.port_local {
        port
    } else {
        port_config.port_remote
    };
    

    // status manage
    let has_port = WEB_SESSION.port.read().await.contains_key(&port_local);
    let res_msg = match (req_status, has_port) {
        (false, true) => {
            if let Some(s) = WEB_SESSION.port.write().await.remove(&port_local) {
                let _ = s.killer.send(true);
            }
            format!("{port_local}端口转发关闭成功")
        },
        (false, false) => {
            format!("{port_local}端口转发已关闭")
        },
        (true, false) => {
            let (kill_tx, kill_rx) = kill_channel(false);
            let port_config_clone = port_config.clone();
            WEB_SESSION.port.write().await.insert(
                port_local,
                PortStorage {
                    killer: kill_tx,
                    meta: PortData {
                        token: token.to_string(),
                        local: port_local,
                        remote: port_config.port_remote,
                        info: machine_config.to_string(),
                        machine: machine_config.machine_token.clone(),
                    }
                }
            );
            spawn(move || {
                port_config_clone.client_handle_before(msg_func_none, Some((kill_rx, machine_config)))
            });
            format!("{port_local}端口转发启动成功")
        },
        (true, true) => {
            format!("{port_local}端口转发已启动")
        }
    };

    let json = {
        let s = WEB_SESSION.port.read().await;
        let data = s.values()
            .filter(| &v | v.meta.token.eq(token))
            .map(| v | &v.meta)
            .collect::<Vec<_>>();
        let res_value = json!({
            "msg": res_msg,
            "data": data,
        });
        json!(res_value).to_string()
    };
    let res = Response::builder()
        .status(StatusCode::OK)
        .header(header::CONTENT_TYPE, "application/json")
        .body(response_body(&json, token)).unwrap();
    Ok(res)
}
